package cn.sq.musicserver.music.controller;


import cn.sq.musicserver.config.ResponseBean;
import cn.sq.musicserver.config.SQConstant;
import cn.sq.musicserver.config.StatusCode;
import cn.sq.musicserver.config.base.BaseController;
import cn.sq.musicserver.exception.FileChangeExeception;
import cn.sq.musicserver.exception.PlugError;
import cn.sq.musicserver.music.entity.DownloadParam;
import cn.sq.musicserver.music.entity.SqMusic;
import cn.sq.musicserver.music.service.impl.SqMusicServiceImpl;
import cn.sq.musicserver.playlist.service.ISqPlayService;
import cn.sq.musicserver.playlist.service.impl.SqMuiscPlayServiceImpl;
import cn.sq.musicserver.plug.entity.PlugSearchResult;
import cn.sq.musicserver.plug.model.jsososo.JsososoHander;
import cn.sq.musicserver.plug.model.jsososo.entity.LyricParam;
import cn.sq.musicserver.plug.model.neteasecloudmusic.NeteaseCloudMusicHander;
import cn.sq.musicserver.plug.model.qqmusicapi.QQMusicApiHander;
import cn.sq.musicserver.plug.model.wpmusicapi.WPHander;
import cn.sq.musicserver.set.entity.SqSet;
import cn.sq.musicserver.set.service.impl.SqSetServiceImpl;
import cn.sq.musicserver.utils.FileUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import com.github.xiaoymin.knife4j.annotations.DynamicParameter;
import com.github.xiaoymin.knife4j.annotations.DynamicParameters;
import com.google.gson.Gson;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.ToString;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authz.annotation.RequiresAuthentication;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.HashMap;
import java.util.List;
import java.util.UUID;

/**
 * <p>
 * 前端控制器
 * </p>
 *
 * @author SQ
 * @since 2020-12-11
 */
@Slf4j
@RestController
@RequestMapping(value = "/music", method = RequestMethod.POST)
@Api(value = "音乐", tags = {"音乐"})
@ToString
public class SqMusicController extends BaseController<SqMusic, SqMusicServiceImpl> {
    @Autowired
    SqSetServiceImpl sqSetService;
    //插件注入 以后用插件库实现 解耦
    @Autowired
    JsososoHander jsososoHander;
    @Autowired
    WPHander wpHander;
    @Autowired
    QQMusicApiHander qqMusicApiHander;
    @Autowired
    NeteaseCloudMusicHander neteaseCloudMusicHander;

    @Autowired
    ISqPlayService sqPlayService;


    @RequiresAuthentication
    @ApiOperation(value = "添加音乐")
    @RequestMapping("save")
    @ApiOperationSupport(params = @DynamicParameters(name = "参考对象(SqMusic)", properties = {
            @DynamicParameter(name = "file", value = "上传文件对象", example = "", required = true, dataTypeClass = MultipartFile.class),
            @DynamicParameter(name = "music", value = "音乐信息", example = "", required = true, dataTypeClass = SqMusic.class),
    }))
    public ResponseBean save(@RequestParam(value = "file") MultipartFile file, @RequestBody SqMusic music) throws FileChangeExeception {
        String newpath = UUID.randomUUID().toString() + FileUtil.getFileSuffix(file.getOriginalFilename());
        if (FileUtil.multipartFileToFile(file, newpath)) {
            music.setMusicPath(newpath);
        }
        boolean add = super.add(music);
        log.debug("添加音乐：" + add);

        return StatusCode.successResponseBean(add);
    }

    @RequiresAuthentication
    @ApiOperation(value = "删除音乐", notes = "根据指定的条件删除")
    @ApiOperationSupport(params = @DynamicParameters(name = "参考对象(SqMusic)", properties = {
            @DynamicParameter(name = "map", value = "音乐信息对象", example = "", required = true, dataTypeClass = SqMusic.class),
    }))
    @RequestMapping("del")
    public ResponseBean delete(@RequestBody HashMap<String, String> map) {
        boolean del = super.del(map);
        log.debug("删除音乐:" + del);
        return StatusCode.successResponseBean(del);
    }

    @RequiresAuthentication
    @ApiOperation(value = "修改音乐", notes = "根据指定的条件修改")
    @ApiOperationSupport(params = @DynamicParameters(name = "参考对象(SqMusic)", properties = {
            @DynamicParameter(name = "map", value = "音乐信息对象", example = "", required = true, dataTypeClass = SqMusic.class),
    }))
    @RequestMapping("modify")
    public ResponseBean modify(@RequestBody HashMap<String, String> map) {
        boolean update = super.update(map);
        log.debug("修改音乐:" + update);
        return StatusCode.successResponseBean(update);
    }

    @RequiresAuthentication
    @ApiOperation(value = "根据条件查询音乐信息")
    @ApiOperationSupport(params = @DynamicParameters(name = "页面对象(IPage扩展对象)", properties = {
            @DynamicParameter(name = "pagesize", value = "每页长度", example = "10", required = true, dataTypeClass = String.class),
            @DynamicParameter(name = "pageindex", value = "第几页", example = "1", required = true, dataTypeClass = String.class),
            @DynamicParameter(name = "ascs", value = "正序字段", required = false, dataTypeClass = String.class),
            @DynamicParameter(name = "desc", value = "倒叙字段", required = false, dataTypeClass = String.class),
    }))
    @RequestMapping("get_list_by_page")
    public ResponseBean get_list_by_page(@RequestBody HashMap<String, String> data) {
        IPage<SqMusic> IPage = super.base_get_list_by_page(data);
        return StatusCode.successResponseBean(IPage);
    }

    @RequiresAuthentication
    @ApiOperation(value = "网络音乐搜索", notes = "使用插件进行网络上资源搜索非自己的音乐")
    @ApiOperationSupport(params = @DynamicParameters(name = "网络音乐搜索", properties = {
            @DynamicParameter(name = "UUID", value = "有UUID则是从自己的音乐列表中找出指定的进行数据的整理 与keywords二选一传递", example = "UUID", required = false, dataTypeClass = String.class),
            @DynamicParameter(name = "keywords", value = "搜索关键字 例如 星晴 周杰伦 与UUID二选一传递", example = "星晴 周杰伦", required = false, dataTypeClass = String.class),
            @DynamicParameter(name = "plugName", value = "搜索类型(插件名称) 目前支持QQ", required = true, example = "qq", dataTypeClass = String.class),
            @DynamicParameter(name = "pageIndex", value = "当前页码", required = true, example = "qq", dataTypeClass = String.class),
            @DynamicParameter(name = "pageSize", value = "每页多少条", required = true, example = "qq", dataTypeClass = String.class),
            @DynamicParameter(name = "plugData", value = "传递给插件的参数 写在和keywords同级即可", required = false, example = "qq", dataTypeClass = HashMap.class),
    }))
    @RequestMapping("musicsearch")
    public ResponseBean musicsearch(@RequestBody HashMap<String, Object> map) throws PlugError {
        //有UUID是搜索歌曲模式
        String uuid = null;
        try {
            uuid = map.get("UUID").toString();
        } catch (Exception e) {
        }
        String keywords = map.get("keywords").toString();
        String p = map.get("plugName").toString();
        System.out.println(p);
        if (uuid != null && !uuid.equals("")) {
            SqMusic byId = super.sService.getById(uuid);
            keywords = byId.getMusicName() + " " + byId.getMusicArtists();
        }
        PlugSearchResult plugSearchResult = null;
        //获取插件设置
        List<SqSet> setType = sqSetService.list(new QueryWrapper<SqSet>().eq("SetType", "Plug-" + p).orderByDesc("SetIndex"));
        if (p.equalsIgnoreCase("Jsososo")) {
            plugSearchResult = jsososoHander.musicInfoSearc(Integer.parseInt(map.get("pageSize").toString()), Integer.parseInt(map.get("pageIndex").toString()), keywords, null, setType, (HashMap) map.get("plugData"));
        } else if (p.equalsIgnoreCase("QQMuiscApi")) {
            plugSearchResult = qqMusicApiHander.musicInfoSearc(Integer.parseInt(map.get("pageSize").toString()), Integer.parseInt(map.get("pageIndex").toString()), map.get("keywords").toString(), null, setType, (HashMap) map.get("plugData"));

        } else if (p.equalsIgnoreCase("NeteaseCloudMusic")) {
            plugSearchResult = neteaseCloudMusicHander.musicInfoSearc(Integer.parseInt(map.get("pageSize").toString()), Integer.parseInt(map.get("pageIndex").toString()), map.get("keywords").toString(), null, setType, (HashMap) map.get("plugData"));

        } else if (p.equalsIgnoreCase("WPMuiscApi")) {
            plugSearchResult = wpHander.musicInfoSearc(Integer.parseInt(map.get("pageSize").toString()), Integer.parseInt(map.get("pageIndex").toString()), map.get("keywords").toString(), null, setType, (HashMap) map.get("plugData"));
        }
        return plugSearchResult == null ? StatusCode.errorResponseBean("请选择插件") : StatusCode.successResponseBean(plugSearchResult);
    }

    @RequiresAuthentication
    @ApiOperation(value = "从网络中下载音乐", notes = "使用插件从网络上进行音乐的下载(禁止使用下载图片)")
//    @ApiOperationSupport( data = DownloadParam.class)
    @RequestMapping("downloadLocal")
    public ResponseBean downloadLocal(@RequestBody DownloadParam downloadParam) throws Exception {
        //禁止使用下载图片
//        downloadParam.setDownliadMusicImage(false);
        String plugName = downloadParam.getPlugName().toLowerCase();
//        ResponseBean responseBean =null;
        SqMusic sqMusic=null;
        if (plugName.contains("jsososo")) {
            sqMusic =  jsososoHander.musicDownload(downloadParam);
        } else if (plugName.contains("qqmuiscapi")) {
            sqMusic= qqMusicApiHander.musicDownload(downloadParam);
//            responseBean = StatusCode.successResponseBean(qqMusicApiHander.musicDownload(downloadParam));

        } else if (plugName.contains("neteasecloudmusic")) {
            sqMusic = neteaseCloudMusicHander.musicDownload(downloadParam);

        } else if (plugName.contains("wpmuiscapi")) {
            sqMusic = wpHander.musicDownload(downloadParam);
        }
        if (sqMusic==null){
            return StatusCode.errorResponseBean("请选择插件");
        }else{
            if (!downloadParam.isTemp()&&downloadParam.getIsSave()&&downloadParam.getPlayUUID()!=null&&!downloadParam.getPlayUUID().equals("")&&sqMusic.getUuid()!=null&&!sqMusic.getUuid().equals("")){
                sqPlayService.addMusicToPlayList(downloadParam.getPlayUUID(),sqMusic.getUuid());
            }

            return  StatusCode.successResponseBean(sqMusic);
        }


    }


    @RequiresAuthentication
    @ApiOperation(value = "从网络中下载歌词", notes = "使用插件从网络上进行歌词的下载")
    @ApiOperationSupport(params = @DynamicParameters(name = "从网络中下载歌词", properties = {
            @DynamicParameter(name = "lyricParam", value = "下载歌词对象", example = "", required = true, dataTypeClass = LyricParam.class),
    }))
    @RequestMapping("musiclyric")
    public ResponseBean musiclyric(@RequestBody LyricParam lyricParam) throws Exception {

        if (lyricParam.getPlugName().equalsIgnoreCase("Jsososo")) {
            return StatusCode.successResponseBean(jsososoHander.MusiclyricDownload(lyricParam));
        } else if (lyricParam.getPlugName().equalsIgnoreCase("QQMuiscApi")) {
            return StatusCode.successResponseBean(qqMusicApiHander.MusiclyricDownload(lyricParam));

        } else if (lyricParam.getPlugName().equalsIgnoreCase("NeteaseCloudMusic")) {
            return StatusCode.successResponseBean(neteaseCloudMusicHander.MusiclyricDownload(lyricParam));

        } else if (lyricParam.getPlugName().equalsIgnoreCase("WPMuiscApi")) {
            return StatusCode.successResponseBean(wpHander.MusiclyricDownload(lyricParam));
        }
        return StatusCode.errorResponseBean("请选择插件");
    }

    @RequestMapping(value = "playMusic", method = {RequestMethod.GET, RequestMethod.POST})
    public void playMusic(HttpServletRequest request, HttpServletResponse response, String musicname, Boolean istemp) throws Exception {
        // 获取Header里面的Range内容, 可选项, 可为空
        String basepath;
        if (istemp) {
            basepath = SQConstant.SYSTEM_TEMPDOWNLOAD_DIR + File.separator;
        } else {
            basepath = SQConstant.SYSTEM_DOWNLOAD_DIR + File.separator;
        }
        // 测试用文件
        File downloadFile = new File(basepath + musicname);
        if (!downloadFile.exists()) {
            response.setCharacterEncoding("utf-8");
            response.setContentType("application/json; charset=utf-8");
            PrintWriter writer = null;
            try {
                writer = response.getWriter();
            } catch (IOException ioException) {

            }
            Gson gson = new Gson();
            writer.write(gson.toJson(StatusCode.errorResponseBean("无此文件")));
        } else {
            ServletContext context = request.getServletContext();
            // get MIME type of the file
            String mimeType = context.getMimeType(basepath + musicname);
            if (mimeType == null) {
                // set to binary type if MIME mapping not found
                mimeType = "application/octet-stream";
            }
            String agent = request.getHeader("USER-AGENT"); //获取浏览器的信息
            try {
                if (agent != null && agent.toLowerCase().indexOf("firefox") > 0) {
                    //火狐浏览器自己会对URL进行一次URL转码所以区别处理
                    response.setHeader("Content-Disposition",
                            "attachment; filename=" + new String(musicname.getBytes("GB2312"), "ISO-8859-1"));
                } else if (agent.toLowerCase().indexOf("safari") > 0) {
                    //苹果浏览器需要用ISO 而且文件名得用UTF-8
                    response.setHeader("Content-Disposition",
                            "attachment; filename=" + new String(musicname.getBytes("UTF-8"), "ISO-8859-1"));
                } else {
                    //其他的浏览器
                    response.setHeader("Content-Disposition",
                            "attachment; filename=\"" + java.net.URLEncoder.encode(musicname, "UTF-8"));
                }
            } catch (Exception e) {
                response.setHeader("Content-Disposition",
                        "attachment; filename=\"" + java.net.URLEncoder.encode(musicname, "UTF-8"));
            }

            // set content attributes for the response
            response.setContentType(mimeType);
            response.setCharacterEncoding("UTF-8");
            // response.setContentLength((int) downloadFile.length());

            // set headers for the response
//        String headerKey = "Content-Disposition";
//        String headerValue = String.format("attachment; filename=\"%s\"",musicname);
//        response.setHeader(headerKey, headerValue);
            // 解析断点续传相关信息
            response.setHeader("Accept-Ranges", "bytes");
            long downloadSize = downloadFile.length();
            long fromPos = 0, toPos = 0;
            if (request.getHeader("Range") == null) {
                response.setHeader("Content-Length", downloadSize + "");
            } else {
                // 若客户端传来Range，说明之前下载了一部分，设置206状态(SC_PARTIAL_CONTENT)
                response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
                String range = request.getHeader("Range");
                String bytes = range.replaceAll("bytes=", "");
                String[] ary = bytes.split("-");
                fromPos = Long.parseLong(ary[0]);
                if (ary.length == 2) {
                    toPos = Long.parseLong(ary[1]);
                }
                int size;
                if (toPos > fromPos) {
                    size = (int) (toPos - fromPos);
                } else {
                    size = (int) (downloadSize - fromPos);
                }
                response.setHeader("Content-Length", size + "");
                downloadSize = size;
            }
            // Copy the stream to the response's output stream.
            RandomAccessFile in = null;
            OutputStream out = null;
            try {
                in = new RandomAccessFile(downloadFile, "rw");
                // 设置下载起始位置
                if (fromPos > 0) {
                    in.seek(fromPos);
                }
                // 缓冲区大小
                int bufLen = (int) (downloadSize < 2048 ? downloadSize : 2048);
                byte[] buffer = new byte[bufLen];
                int num;
                int count = 0; // 当前写到客户端的大小v
                out = response.getOutputStream();
                while ((num = in.read(buffer)) != -1) {
                    out.write(buffer, 0, num);
                    count += num;
                    //处理最后一段，计算不满缓冲区的大小
                    if (downloadSize - count < bufLen) {
                        bufLen = (int) (downloadSize - count);
                        if (bufLen == 0) {
                            break;
                        }
                        buffer = new byte[bufLen];
                    }
                }
                response.flushBuffer();
            } catch (IOException e) {
                log.debug("数据被暂停或中断。");
//            e.printStackTrace();
            } finally {
                if (null != out) {
                    try {
                        out.close();
                    } catch (IOException e) {
                        log.debug("数据被暂停或中断。");
//                    e.printStackTrace();
                    }
                }
                if (null != in) {
                    try {
                        in.close();
                    } catch (IOException e) {
                        log.debug("数据被暂停或中断。");
//                    e.printStackTrace();
                    }
                }
            }
        }
    }

    @Deprecated
    @RequestMapping(value = "downloadMusic", method = {RequestMethod.GET, RequestMethod.POST})
    public void downloadMusic(HttpServletRequest request, HttpServletResponse response, String musicname, Boolean istemp) {
        // 获取Header里面的Range内容, 可选项, 可为空
        String basepath;
        if (istemp) {
            basepath = SQConstant.SYSTEM_TEMPDOWNLOAD_DIR + File.separator;
        } else {
            basepath = SQConstant.SYSTEM_DOWNLOAD_DIR + File.separator;
        }
        // 测试用文件
        File downloadFile = new File(basepath + musicname);
        response.reset();
        if (!downloadFile.exists()) {
            response.setCharacterEncoding("utf-8");
            response.setContentType("application/json; charset=utf-8");
            PrintWriter writer = null;
            try {
                writer = response.getWriter();
            } catch (IOException ioException) {

            }
            Gson gson = new Gson();
            writer.write(gson.toJson(StatusCode.errorResponseBean("无此文件")));
        } else {
            ServletContext context = request.getServletContext();
            // get MIME type of the file
            String mimeType = context.getMimeType(basepath + musicname);
            if (mimeType == null) {
                // set to binary type if MIME mapping not found
                mimeType = "application/octet-stream";
            }

            String agent = request.getHeader("USER-AGENT"); //获取浏览器的信息
            try {
                if (agent != null && agent.toLowerCase().indexOf("firefox") > 0) {
                    //火狐浏览器自己会对URL进行一次URL转码所以区别处理
                    response.setHeader("Content-Disposition",
                            "attachment; filename=" + new String(musicname.getBytes("GB2312"), "ISO-8859-1"));
                } else if (agent.toLowerCase().indexOf("safari") > 0) {
                    //苹果浏览器需要用ISO 而且文件名得用UTF-8
                    response.setHeader("Content-Disposition",
                            "attachment; filename=" + new String(musicname.getBytes("UTF-8"), "ISO-8859-1"));
                } else {
                    //其他的浏览器

                    response.setHeader("Content-Disposition",
                            "attachment; filename=\"" + java.net.URLEncoder.encode(musicname, "UTF-8"));
                }
            } catch (UnsupportedEncodingException e) {
                try {
                    response.setHeader("Content-Disposition",
                            "attachment; filename=\"" + java.net.URLEncoder.encode(musicname, "UTF-8"));
                } catch (UnsupportedEncodingException unsupportedEncodingException) {
                    unsupportedEncodingException.printStackTrace();
                }
            }
            // set content attributes for the response
            response.setContentType(mimeType);
            response.setCharacterEncoding("UTF-8");
            InputStream fis = null;
            try {
                fis = new BufferedInputStream(new FileInputStream(downloadFile));
                byte[] buffer = new byte[fis.available()];
                fis.read(buffer);
                response.addHeader("Content-Length", "" + downloadFile.length());
                OutputStream toClient = new BufferedOutputStream(response.getOutputStream());
                toClient.write(buffer);
                toClient.flush();
                toClient.close();
                // 清空response
            } catch (IOException e) {
                e.printStackTrace();
            }

            // response.setContentLength((int) downloadFile.length());
        }
    }
}
